// Copyright (c) 2023 Presto Labs Pte. Ltd.
// Author: tianqiang

#pragma once

#include "coin2/exchange/base/api_util/api_signature.h"
#include "coin2/exchange/base/api_util/json_writer.h"

class BitRestAuth : public BaseRestAuth {
 public:
  explicit BitRestAuth(
      const std::string& key_filepath,
      const std::string& host,
      const std::string& port,
      const std::string& bind_ip)
      : key_(AuthKey::FromFile(key_filepath)), host_(host), port_(port), bind_ip_(bind_ip) {
    header_.emplace_back("Content-Type", "application/json");
    header_.emplace_back("X-Bit-Access-Key", key_.access_key());
  }

  explicit BitRestAuth(
      const std::string& key_filepath,
      const std::string& host,
      int32_t port,
      const std::string& bind_ip)
      : BitRestAuth(key_filepath, host, std::to_string(port), bind_ip) {}

  AsioHttpContext* CreateRequestByGetWithSignature(
      const std::string& url_path,
      UrlParamsBuilder* builder) override {
    std::string post_body = builder->ComputePostBodyAsQueryString();
    CHECK(post_body.empty());

    builder->PutGet("timestamp", GetCurrentTimestamp() / 1000000);

    std::string sign = GenSignature(url_path, builder->ComputeQueryString());

    builder->PutGet("signature", sign);

    std::string target = url_path + "?" + builder->ComputeQueryString();

    return AsioHttpContext::NewGet(host_, port_, bind_ip_, target, header_);
  }

  AsioHttpContext* CreateRequestByPostWithSignature(
      const std::string& url_path,
      UrlParamsBuilder* builder) override {
    std::string query_string = builder->ComputeQueryString();
    CHECK(query_string.empty());

    builder->PutPost<true>("timestamp", GetCurrentTimestamp() / 1000000);

    std::string sign = GenSignature(url_path, builder->ComputePostBodyAsQueryString());

    builder->PutPost("signature", sign);

    std::string post_body = builder->ComputePostBody();

    return AsioHttpContext::NewPost(host_, port_, bind_ip_, url_path, header_, post_body);
  }

  AsioHttpContext* CreateRequestByDeleteWithSignature(
      const std::string& url_path,
      UrlParamsBuilder* builder) override {
    return nullptr;
  }

  AsioHttpContext* CreateRequestByPutWithSignature(
      const std::string& address,
      UrlParamsBuilder* builder) override {
    return nullptr;
  }

 protected:
  AuthKey key_;
  std::string host_;
  std::string port_;
  std::string bind_ip_;
  std::vector<std::pair<std::string, std::string>> header_;

 private:
  std::string GenSignature(const std::string& path, const std::string& param_str) {
    std::string str_to_sign = path + "&" + param_str;

    return ApiSignatureUtil::GetSignatureByHexHmacSHA256(str_to_sign, key_.secret_key());
  }
};
